home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tcl / tclUnixNotfy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-01  |  8.4 KB  |  323 lines

  1. /* 
  2.  * tclUnixNotify.c --
  3.  *
  4.  *    This file contains Unix-specific procedures for the notifier,
  5.  *    which is the lowest-level part of the Tcl event loop.  This file
  6.  *    works together with ../generic/tclNotify.c.
  7.  *
  8.  * Copyright (c) 1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tclUnixNotfy.c 1.30 96/03/22 12:45:31
  14.  */
  15.  
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18. #include <signal.h> 
  19.  
  20. /*
  21.  * The information below is used to provide read, write, and
  22.  * exception masks to select during calls to Tcl_DoOneEvent.
  23.  */
  24.  
  25. static fd_mask checkMasks[3*MASK_SIZE];
  26.                 /* This array is used to build up the masks
  27.                  * to be used in the next call to select.
  28.                  * Bits are set in response to calls to
  29.                  * Tcl_WatchFile. */
  30. static fd_mask readyMasks[3*MASK_SIZE];
  31.                 /* This array reflects the readable/writable
  32.                  * conditions that were found to exist by the
  33.                  * last call to select. */
  34. static int numFdBits;        /* Number of valid bits in checkMasks
  35.                  * (one more than highest fd for which
  36.                  * Tcl_WatchFile has been called). */
  37.  
  38. /*
  39.  * Static routines in this file:
  40.  */
  41.  
  42. static int    MaskEmpty _ANSI_ARGS_((long *maskPtr));
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * Tcl_WatchFile --
  48.  *
  49.  *    Arrange for Tcl_DoOneEvent to include this file in the masks
  50.  *    for the next call to select.  This procedure is invoked by
  51.  *    event sources, which are in turn invoked by Tcl_DoOneEvent
  52.  *    before it invokes select.
  53.  *
  54.  * Results:
  55.  *    None.
  56.  *
  57.  * Side effects:
  58.  *    
  59.  *    The notifier will generate a file event when the I/O channel
  60.  *    given by fd next becomes ready in the way indicated by mask.
  61.  *    If fd is already registered then the old mask will be replaced
  62.  *    with the new one.  Once the event is sent, the notifier will
  63.  *    not send any more events about the fd until the next call to
  64.  *    Tcl_NotifyFile. 
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68.  
  69. void
  70. Tcl_WatchFile(file, mask)
  71.     Tcl_File file;    /* Generic file handle for a stream. */
  72.     int mask;            /* OR'ed combination of TCL_READABLE,
  73.                  * TCL_WRITABLE, and TCL_EXCEPTION:
  74.                  * indicates conditions to wait for
  75.                  * in select. */
  76. {
  77.     int fd, type, index;
  78.     fd_mask bit;
  79.  
  80.     fd = (int) Tcl_GetFileInfo(file, &type);
  81.  
  82.     if (type != TCL_UNIX_FD) {
  83.     panic("Tcl_WatchFile: unexpected file type");
  84.     }
  85.  
  86.     if (fd >= FD_SETSIZE) {
  87.     panic("Tcl_WatchFile can't handle file id %d", fd);
  88.     }
  89.  
  90.     index = fd/(NBBY*sizeof(fd_mask));
  91.     bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
  92.     if (mask & TCL_READABLE) {
  93.     checkMasks[index] |= bit;
  94.     }
  95.     if (mask & TCL_WRITABLE) {
  96.     (checkMasks+MASK_SIZE)[index] |= bit;
  97.     }
  98.     if (mask & TCL_EXCEPTION) {
  99.     (checkMasks+2*(MASK_SIZE))[index] |= bit;
  100.     }
  101.     if (numFdBits <= fd) {
  102.     numFdBits = fd+1;
  103.     }
  104. }
  105.  
  106. /*
  107.  *----------------------------------------------------------------------
  108.  *
  109.  * Tcl_FileReady --
  110.  *
  111.  *    Indicates what conditions (readable, writable, etc.) were
  112.  *    present on a file the last time the notifier invoked select.
  113.  *    This procedure is typically invoked by event sources to see
  114.  *    if they should queue events.
  115.  *
  116.  * Results:
  117.  *    The return value is 0 if none of the conditions specified by mask
  118.  *    was true for fd the last time the system checked.  If any of the
  119.  *    conditions were true, then the return value is a mask of those
  120.  *    that were true.
  121.  *
  122.  * Side effects:
  123.  *    None.
  124.  *
  125.  *----------------------------------------------------------------------
  126.  */
  127.  
  128. int
  129. Tcl_FileReady(file, mask)
  130.     Tcl_File file;    /* Generic file handle for a stream. */
  131.     int mask;            /* OR'ed combination of TCL_READABLE,
  132.                  * TCL_WRITABLE, and TCL_EXCEPTION:
  133.                  * indicates conditions caller cares about. */
  134. {
  135.     int index, result, type, fd;
  136.     fd_mask bit;
  137.  
  138.     fd = (int) Tcl_GetFileInfo(file, &type);
  139.     if (type != TCL_UNIX_FD) {
  140.     panic("Tcl_FileReady: unexpected file type");
  141.     }
  142.  
  143.     index = fd/(NBBY*sizeof(fd_mask));
  144.     bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
  145.     result = 0;
  146.     if ((mask & TCL_READABLE) && (readyMasks[index] & bit)) {
  147.     result |= TCL_READABLE;
  148.     }
  149.     if ((mask & TCL_WRITABLE) && ((readyMasks+MASK_SIZE)[index] & bit)) {
  150.     result |= TCL_WRITABLE;
  151.     }
  152.     if ((mask & TCL_EXCEPTION) && ((readyMasks+(2*MASK_SIZE))[index] & bit)) {
  153.     result |= TCL_EXCEPTION;
  154.     }
  155.     return result;
  156. }
  157.  
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * MaskEmpty --
  162.  *
  163.  *    Returns nonzero if mask is empty (has no bits set).
  164.  *
  165.  * Results:
  166.  *    Nonzero if the mask is empty, zero otherwise.
  167.  *
  168.  * Side effects:
  169.  *    None
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173.  
  174. static int
  175. MaskEmpty(maskPtr)
  176.     long *maskPtr;
  177. {
  178.     long *runPtr, *tailPtr;
  179.     int found, sz;
  180.  
  181.     sz = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
  182.     for (runPtr = maskPtr, tailPtr = maskPtr + sz, found = 0;
  183.              runPtr < tailPtr;
  184.              runPtr++) {
  185.         if (*runPtr != 0) {
  186.             found = 1;
  187.             break;
  188.         }
  189.     }
  190.     return !found;    
  191. }
  192.  
  193. /*
  194.  *----------------------------------------------------------------------
  195.  *
  196.  * Tcl_WaitForEvent --
  197.  *
  198.  *    This procedure does the lowest level wait for events in a
  199.  *    platform-specific manner.  It uses information provided by
  200.  *    previous calls to Tcl_WatchFile, plus the timePtr argument,
  201.  *    to determine what to wait for and how long to wait.
  202.  *
  203.  * Results:
  204.  *    The return value is normally TCL_OK.  However, if there are
  205.  *    no events to wait for (e.g. no files and no timers) so that
  206.  *    the procedure would block forever, then it returns TCL_ERROR.
  207.  *
  208.  * Side effects:
  209.  *    May put the process to sleep for a while, depending on timePtr.
  210.  *    When this procedure returns, an event of interest to the application
  211.  *    has probably, but not necessarily, occurred.
  212.  *
  213.  *----------------------------------------------------------------------
  214.  */
  215.  
  216. int
  217. Tcl_WaitForEvent(timePtr)
  218.     Tcl_Time *timePtr;        /* Specifies the maximum amount of time
  219.                  * that this procedure should block before
  220.                  * returning.  The time is given as an
  221.                  * interval, not an absolute wakeup time.
  222.                  * NULL means block forever. */
  223. {
  224.     struct timeval timeout, *timeoutPtr;
  225.     int numFound;
  226.  
  227.     memcpy((VOID *) readyMasks, (VOID *) checkMasks,
  228.         3*MASK_SIZE*sizeof(fd_mask));
  229.     if (timePtr == NULL) {
  230.     if ((numFdBits == 0) || (MaskEmpty((long *) readyMasks))) {
  231.         return TCL_ERROR;
  232.     }
  233.     timeoutPtr = NULL;
  234.     } else {
  235.     timeoutPtr = &timeout;
  236.     timeout.tv_sec = timePtr->sec;
  237.     timeout.tv_usec = timePtr->usec;
  238.     }
  239.     numFound = select(numFdBits, (SELECT_MASK *) &readyMasks[0],
  240.         (SELECT_MASK *) &readyMasks[MASK_SIZE],
  241.         (SELECT_MASK *) &readyMasks[2*MASK_SIZE], timeoutPtr);
  242.  
  243.     /*
  244.      * Some systems don't clear the masks after an error, so
  245.      * we have to do it here.
  246.      */
  247.  
  248.     if (numFound == -1) {
  249.     memset((VOID *) readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
  250.     }
  251.  
  252.     /*
  253.      * Reset the check masks in preparation for the next call to
  254.      * select.
  255.      */
  256.  
  257.     numFdBits = 0;
  258.     memset((VOID *) checkMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
  259.     return TCL_OK;
  260. }
  261.  
  262. /*
  263.  *----------------------------------------------------------------------
  264.  *
  265.  * Tcl_Sleep --
  266.  *
  267.  *    Delay execution for the specified number of milliseconds.
  268.  *
  269.  * Results:
  270.  *    None.
  271.  *
  272.  * Side effects:
  273.  *    Time passes.
  274.  *
  275.  *----------------------------------------------------------------------
  276.  */
  277.  
  278. void
  279. Tcl_Sleep(ms)
  280.     int ms;            /* Number of milliseconds to sleep. */
  281. {
  282.     static struct timeval delay;
  283.     Tcl_Time before, after;
  284.  
  285.     /*
  286.      * The only trick here is that select appears to return early
  287.      * under some conditions, so we have to check to make sure that
  288.      * the right amount of time really has elapsed.  If it's too
  289.      * early, go back to sleep again.
  290.      */
  291.  
  292.     TclGetTime(&before);
  293.     after = before;
  294.     after.sec += ms/1000;
  295.     after.usec += (ms%1000)*1000;
  296.     if (after.usec > 1000000) {
  297.     after.usec -= 1000000;
  298.     after.sec += 1;
  299.     }
  300.     while (1) {
  301.     delay.tv_sec = after.sec - before.sec;
  302.     delay.tv_usec = after.usec - before.usec;
  303.     if (delay.tv_usec < 0) {
  304.         delay.tv_usec += 1000000;
  305.         delay.tv_sec -= 1;
  306.     }
  307.  
  308.     /*
  309.      * Special note:  must convert delay.tv_sec to int before comparing
  310.      * to zero, since delay.tv_usec is unsigned on some platforms.
  311.      */
  312.  
  313.     if ((((int) delay.tv_sec) < 0)
  314.         || ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
  315.         break;
  316.     }
  317.     (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
  318.         (SELECT_MASK *) 0, &delay);
  319.     TclGetTime(&before);
  320.     }
  321. }
  322.  
  323.